home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
301-325
/
disk_313
/
uucp
/
uucp1.lzh
/
src
/
getty
/
getty.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-01-08
|
20KB
|
986 lines
/*
* GETTY.C
*
* (c)Copyright 1989, Matthew Dillon, All Rights Reserved
*
* Uses:
* GETTY:PASSWD
* GETTY:LOGFILE
* GETTY:Getty-Header
*
* GETTY <options> <modem-commands>
*
* -Sdevicenam Tells GETTY which serial.device to use, default
* serial.device
*
* -Uunitnum Tells GETTY which unit number to use, default 0
*
* -A Always talk to the modem at the first baud
* rate in the -B list and ignore the baud rate
* in the CONNECT message.
*
* -7 use SERF_7WIRE while online.
*
* -Bn Set baud rate. If specified multiple times the
* first one is the default and remaining ones
* switched to when a BREAK is received after a
* connect. Also determines how CONNECT messages
* are interpreted. A CONNECT with no number uses
* the first -B entry while CONNECTs with numbers
* use those numbers regardless of any -B entries.
*
* -Mc Set modem type:
* c = m = multimodem
* h = hays
* d = dumb (no AT or +++ cmds are ever sent),
* normally used with only one specified
* baud rate.
*
* -m1 Turn on the modem speaker during dialing/connect
* (default is -m0)
*
* -h0 Ignore CD (carrier detect), default is to use
* carrier detect.
*
* -c0 Ignore CONNECT message (i.e. you are not connected
* to a modem, usually combined with -h0). Default is
* to expect a CONNECT message.
*
* -d0 do not use DTR to drop connection. Default is
* to drop DTR to drop a connection. If this option
* is chosen the +++ and ATH0 sequence will be used
* to drop a connection.
*
* -xn Set debug level. Also causes log output to go
* to stdout instead of GETTY:LOGFILE
*
* -0 QUIT - Kills any running getty for the specified
* port.
*
* Any fields specified without a '-' are considered modem commands
* used to initialize/reinitialize the modem. Up to 16 fields may
* be specified (each is sent to the modem in 1 second intervals)
*/
#include <exec/types.h>
#include <exec/lists.h>
#include <exec/devices.h>
#include <devices/timer.h>
#include <devices/serial.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <hardware/cia.h>
#include <stdio.h>
#include <stdlib.h>
#include <proto/all.h>
#include <pwd.h>
#include "/version.h"
#include "log.h"
IDENT(".01");
#define arysize(ary) (sizeof(ary)/sizeof((ary)[0]))
#define ST_WAITCD 0
#define ST_CONNECT 1
#define ST_LOGIN 2
#define ST_PASSWD 3
#define ST_RUN 4
typedef struct IORequest IOR;
typedef struct timerequest IOT;
typedef struct IOExtSer IOSER;
typedef struct MsgPort PORT;
typedef struct List LIST;
typedef struct Node NODE;
typedef struct Message MSG;
typedef struct GMsg {
struct Message Msg;
short Cmd;
long Data1;
void *Data2;
} GMsg;
extern struct ProcID *RunPasswdEntry();
char *CopyRight = "(c)Copyright 1989, Matthew Dillon, All Rights Reserved\r\n";
char *ComPortName;
char *DeviceName = "serial.device";
long DeviceUnit = 0;
long NullFH;
char SpeakerLevel = 0;
char AnswerRing = 2; /* default, answer on second ring */
char SpeakerOpt = 0;
char IgnoreCD = 0;
char IgnoreConnect = 0;
char IgnoreDTR = 0;
char BaudAdjust = 0;
char DropOnExit = 1;
char ModemType = 'h';
char ZeroOption = 0;
char Wire7 = 0; /* use 7 wire while online */
char Locked = 0; /* serial port is lcked */
long Bauds[16] = { 9600 }; /* up 16 baud rates */
char *AtFields[16];
PORT *ComPort;
PORT *IoSink; /* Sink for IO reqs. */
long IoSinkMask;
long ComPortMask;
IOT Iot; /* check-carrier */
IOSER Iosr; /* serial read-req */
IOSER Iosw; /* serial write-req */
char IotIP; /* Iot0 in progress */
char IosrIP;
char ScrBuf[256];
char ConnectBuf[64];
char LoginBuf[32];
char PasswdBuf[32];
char RxBuf[32];
char HaveConnectMsg;
char HaveLogin;
char HavePasswd;
short State;
short Index;
short BIndex;
short CountDown;
short GotOffPort;
void SerPuts();
void Set7Wire();
void xexit();
void Disconnect();
void ClearRecv();
void InitModem();
void SetParams();
void DoOptions();
void SerialOff();
CXBRK()
{
return(0);
}
main(ac, av)
char *av[];
{
extern int IAmGetty;
IAmGetty = 1; /* for LockSerialPort()/UnLockSerialPort() */
puts(CopyRight);
fflush(stdout);
LogProgram = "Getty";
LogWho = LoginBuf;
LogFile = "Getty:LOGFILE";
PasswdFile = "Getty:Passwd";
DoOptions(ac, av);
IoSink = CreatePort(NULL, 0);
IoSinkMask = 1 << IoSink->mp_SigBit;
ComPortName = malloc(strlen(DeviceName) + 20);
sprintf(ComPortName, "Getty.%s.%d", DeviceName, DeviceUnit);
Forbid();
if (ComPort = FindPort(ComPortName)) {
GMsg msg;
msg.Cmd = 'O';
msg.Data1 = ac;
msg.Data2 = (void *)av;
msg.Msg.mn_ReplyPort = IoSink;
PutMsg(ComPort, &msg.Msg);
WaitPort(IoSink);
Remove(&msg);
Permit();
puts("Options updated");
xexit(0);
}
ComPort = CreatePort(ComPortName, 0);
Permit();
ComPortMask = 1 << ComPort->mp_SigBit;
NullFH = Open("NULL:", 1006);
if (NullFH == NULL) {
ulog(-1, "GETTY REQUIRES NULL: HANDLER!");
puts("Requires NULL: handler!");
xexit(1);
}
if (LogToStdout == 0) {
freopen("NULL:", "r", stdin);
freopen("NULL:", "w", stdout);
freopen("NULL:", "w", stderr);
}
/*
* Timer Device
*/
Iot.tr_node.io_Message.mn_ReplyPort = IoSink;
if (OpenDevice("timer.device", UNIT_VBLANK, &Iot, 0)) {
Iot.tr_node.io_Device = NULL;
xexit(20);
}
Iot.tr_node.io_Command = TR_ADDREQUEST;
/*
* SERIAL.DEVICE
*/
Iosr.IOSer.io_Message.mn_ReplyPort = IoSink;
Iosr.io_SerFlags = SERF_XDISABLED | SERF_7WIRE | SERF_RAD_BOOGIE | SERF_SHARED;
if (OpenDevice(DeviceName, DeviceUnit, &Iosr, 0)) {
Iosr.IOSer.io_Device = NULL;
xexit(21);
}
Iosw = Iosr;
Iosw.io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE | SERF_SHARED;
Iosw.io_ExtFlags = 0;
Iosw.io_Baud = Bauds[0];
Iosw.io_ReadLen = 8;
Iosw.io_WriteLen = 8;
Iosw.io_StopBits = 1;
SetParams(&Iosw);
/*
* Run Operation
*/
State = ST_WAITCD;
Iot.tr_time.tv_secs = 1;
Iot.tr_time.tv_micro= 0;
IotIP = 1;
SendIO(&Iot);
InitModem();
Signal(FindTask(NULL), IoSinkMask);
for (;;) {
long mask;
IOR *ior;
GMsg *msg;
mask = Wait(SIGBREAKF_CTRL_C | IoSinkMask | ComPortMask);
ulog(2, "State = %d", State);
if (mask & SIGBREAKF_CTRL_C)
break;
if (msg = (GMsg *)GetMsg(ComPort)) {
do {
switch(msg->Cmd) {
case 'O':
DoOptions(msg->Data1, msg->Data2);
break;
}
ReplyMsg((MSG *)msg);
if (ZeroOption)
xexit(0);
} while (msg = (GMsg *)GetMsg(ComPort));
if (State == ST_WAITCD && !GotOffPort)
Disconnect(0);
}
while (ior = (IOR *)GetMsg(IoSink)) {
if (ior == (IOR *)&Iot) {
short diu;
IotIP = 0;
Iot.tr_time.tv_secs = 1;
Iot.tr_time.tv_micro= 0;
/*
* If OpenCnt > 1, disable all processing.
*
* When returns to <= 1 reset serial port.
*/
diu = DeviceInUse();
if (diu) {
if (GotOffPort == 0) {
ulog(-1, "Device in use");
if (Locked)
ulog(-1, "getting off port");
SerialOff();
GotOffPort = 1;
State = ST_WAITCD;
}
SendIO(&Iot);
IotIP = 1;
continue;
}
if (GotOffPort) {
if (Locked == 0) {
LockSerialPort(DeviceName, DeviceUnit);
Locked = 1;
}
GotOffPort = 0;
ulog(-1, "Getty resetting");
SendIO(&Iot);
IotIP = 1;
Disconnect(1);
continue;
}
if (State == ST_WAITCD)
SerialOff();
if (State != ST_WAITCD && IosrIP == 0) {
if (Locked == 0)
LockSerialPort(DeviceName, DeviceUnit);
Locked = 1;
ulog(-1, "Serial Port Locked");
Iosr.IOSer.io_Command = CMD_READ;
Iosr.IOSer.io_Data = (APTR)RxBuf;
Iosr.IOSer.io_Length = 1;
SendIO(&Iosr);
IosrIP = 1;
ulog(1, "Carrier, Getty getting on port");
}
Iosw.IOSer.io_Command = SDCMD_QUERY;
DoIO(&Iosw);
if (IgnoreCD)
Iosw.io_Status &= ~CIAF_COMCD;
/*
* If state connected and we loose carrier, disconnect.
*
* If state connected and timeout occurs disconnect.
*/
if (State != ST_WAITCD) {
if ((Iosw.io_Status & CIAF_COMCD) != 0) {
ulog(1, "Getty, Carrier lost");
Disconnect(0);
} else {
if (--CountDown == 0) {
ulog(1, "Getty, Timeout, Disconnecting");
Disconnect(1);
Iosw.io_Status |= CIAF_COMCD; /* for below */
}
}
}
switch(State) {
case ST_WAITCD:
if ((Iosw.io_Status & CIAF_COMCD) == 0) {
State = ST_CONNECT;
CountDown = 60; /* allow 60 seconds */
ulog(-1, "Carrier Detect");
} else {
Iot.tr_time.tv_secs = 2;
}
break;
case ST_CONNECT:
/*
* Wait for CONNECT message, then send Login:
*/
if (IgnoreConnect && HaveConnectMsg == 0) {
if (Wire7)
Set7Wire(&Iosw);
HaveConnectMsg = 1;
ulog(-1, "Connect");
}
if (HaveConnectMsg) {
FILE *fi;
Delay(50);
ClearRecv();
if (fi = fopen("Getty:Getty-Header", "r")) {
while (fgets(ScrBuf, sizeof(ScrBuf), fi)) {
SerPuts(ScrBuf);
SerPuts("\r");
}
fclose(fi);
}
SerPuts("Login: ");
ulog(-1, "Getty, Connect, Login");
State = ST_LOGIN;
Index = 0;
HaveLogin = 0;
LoginBuf[0] = 0;
}
break;
case ST_LOGIN: /* wait Login: response */
if (HaveLogin) {
if (LoginBuf[0] == 0) {
State = ST_CONNECT;
break;
}
ClearRecv();
PasswdBuf[0] = 0;
/*
* If no password required, else request
* password.
*/
if (CheckLoginAndPassword()) {
HavePasswd = 1;
Index = 0;
State = ST_PASSWD;
} else {
SerPuts("Password: ");
ulog(1, "Getty, Passwd");
State = ST_PASSWD;
HavePasswd = 0;
Index = 0;
}
}
break;
case ST_PASSWD: /* wait Password: response */
if (HavePasswd) {
if (CheckLoginAndPassword()) {
ulog(-1, "login %s", LoginBuf);
/*
* Disable read requests but leave serial
* port locked.
*/
if (IosrIP) {
AbortIO(&Iosr);
WaitIO(&Iosr);
IosrIP = 0;
}
/*
* If run successful, leave read req and
* timer disabled.
*/
RunPasswdEntry();
if (DropOnExit)
Disconnect(1);
else
State = ST_CONNECT;
ulog(-1, "disconnect");
} else {
SerPuts("Login Failed.\r\n\n");
State = ST_CONNECT;
ulog(-1, "LoginFailed user=%s pass=%s", LoginBuf, PasswdBuf);
}
HaveLogin = 0;
HavePasswd= 0;
LoginBuf[0] = 0;
}
break;
}
/*
* Make no read requests while running 3rd party
* program, else resend read request.
*/
if (IotIP == 0) {
IotIP = 1;
SendIO(&Iot);
}
}
/*
* RECEIVED SERIAL READ DATA
*/
if (ior == (IOR *)&Iosr) {
IosrIP = 0;
Iosw.IOSer.io_Command = SDCMD_QUERY;
DoIO(&Iosw);
if (IgnoreCD)
Iosw.io_Status &= ~CIAF_COMCD;
/*
* BREAK used to switch baud rates between allowed
* values
*/
if (Iosw.io_Status & IO_STATF_READBREAK) {
if (BaudAdjust == 0 && (State == ST_LOGIN || State == ST_PASSWD)) {
if (++BIndex == arysize(Bauds))
BIndex = 0;
if (Bauds[BIndex] == 0)
BIndex = 0;
Iosw.io_Baud = Bauds[BIndex];
SetParams(&Iosw);
if (Wire7)
Set7Wire(&Iosw);
ulog(1, "<BREAK> to %d baud", Iosw.io_Baud);
Delay(100);
ClearRecv();
Index = 0;
State = ST_CONNECT;
}
} else
if (Iosr.IOSer.io_Actual == 1) {
char *ptr;
UBYTE c = (UBYTE)RxBuf[0];
ulog(2, "Rx %02x %c", c, (c < 32) ? ' ' : c);
c &= 0x7F;
switch(State) {
case ST_WAITCD: /* looking for CONNECT msg */
case ST_CONNECT: /* looking for CONNECT msg */
ptr = ConnectBuf;
break;
case ST_LOGIN: /* looking for login name */
ptr = LoginBuf;
break;
case ST_PASSWD: /* looking for password */
ptr = PasswdBuf;
break;
}
if (State == ST_LOGIN && HaveLogin)
c = 0;
if (State == ST_PASSWD && HavePasswd)
c = 0;
switch(c) {
case 0:
break;
case 8:
if (State == ST_LOGIN && HaveLogin)
break;
if (Index) {
if (State == ST_LOGIN)
SerPuts("\010 \010");
--Index;
}
break;
case 10:
case 13:
ptr[Index] = 0;
Index = 0;
switch(State) {
case ST_WAITCD:
case ST_CONNECT:
if (strncmp(ptr, "CONNECT", 7)) {
ulog(1, "Looking for CONNECT, got '%s'", ptr);
break;
}
Delay(50);
HaveConnectMsg = 1;
if (BaudAdjust) {
ulog(-1, "Connect Auto-Baud %d", Iosw.io_Baud);
} else {
char *str = ptr + 7;
while (*str && (*str == 9 || *str == ' '))
++str;
if (*str >= '0' && *str <= '9')
Iosw.io_Baud = atoi(str);
else
Iosw.io_Baud = Bauds[0];
SetParams(&Iosw);
ulog(-1, "Connect at %d baud", Iosw.io_Baud);
}
if (Wire7)
Set7Wire(&Iosw);
break;
case ST_LOGIN:
HaveLogin = 1;
SerPuts("\r\n");
ulog(1, "Login: %s", ptr);
break;
case ST_PASSWD:
HavePasswd = 1;
SerPuts("\r\n");
ulog(1, "Password: %s", ptr);
break;
}
break;
default:
if (Index == 31)
break;
if (State == ST_LOGIN) {
char cc[2];
cc[0] = c;
cc[1] = 0;
SerPuts(cc);
}
ptr[Index++] = c;
break;
}
}
if (IosrIP == 0) {
Iosr.IOSer.io_Command = CMD_READ;
Iosr.IOSer.io_Data = (APTR)RxBuf;
Iosr.IOSer.io_Length = 1;
SendIO(&Iosr);
IosrIP = 1;
}
}
}
}
xexit(0);
}
void
SerialOff()
{
if (IosrIP) {
AbortIO(&Iosr);
WaitIO(&Iosr);
IosrIP = 0;
}
if (Locked) {
UnLockSerialPort(DeviceName, DeviceUnit);
Locked = 0;
ulog(1, "Serial Port UnLocked");
}
}
void
xexit(code)
{
if (ComPortMask) {
GMsg *msg;
Forbid();
while (msg = (GMsg *)GetMsg(ComPort))
ReplyMsg((MSG *)msg);
DeletePort(ComPort);
Permit();
}
if (IotIP) {
AbortIO(&Iot);
WaitIO(&Iot);
}
if (Iot.tr_node.io_Device)
CloseDevice(&Iot);
if (IosrIP) {
AbortIO(&Iosr);
WaitIO(&Iosr);
}
if (Iosr.IOSer.io_Device)
CloseDevice(&Iosr);
if (IoSink)
DeletePort(IoSink);
if (NullFH)
Close(NullFH);
if (Locked)
UnLockSerialPort(DeviceName, DeviceUnit);
exit(code);
}
void
SerPuts(str)
char *str;
{
Iosw.IOSer.io_Command = CMD_WRITE;
Iosw.IOSer.io_Data = (APTR)str;
Iosw.IOSer.io_Length = strlen(str);
DoIO(&Iosw);
}
static short RxDisableIP;
void
RxDisable()
{
RxDisableIP = IosrIP;
if (IosrIP) {
AbortIO(&Iosr);
WaitIO(&Iosr);
IosrIP = 0;
}
}
void
RxEnable()
{
if (RxDisableIP && IosrIP == 0) {
Iosr.IOSer.io_Command = CMD_READ;
Iosr.IOSer.io_Data = (APTR)RxBuf;
Iosr.IOSer.io_Length = 1;
SendIO(&Iosr);
IosrIP = 1;
}
}
void
ClearRecv()
{
RxDisable();
ulog(1, "Clear beg");
for (;;) {
Iosr.IOSer.io_Command = SDCMD_QUERY;
DoIO(&Iosr);
if ((Iosr.IOSer.io_Length = Iosr.IOSer.io_Actual) <= 0)
break;
if (Iosr.IOSer.io_Length > sizeof(RxBuf))
Iosr.IOSer.io_Length = sizeof(RxBuf);
Iosr.IOSer.io_Data = (APTR)RxBuf;
Iosr.IOSer.io_Command = CMD_READ;
DoIO(&Iosr);
}
ulog(1, "Clear end");
RxEnable();
}
void
SetParams(ior)
IOSER *ior;
{
int error;
if (IosrIP)
AbortIO(&Iosr);
ior->IOSer.io_Command = SDCMD_SETPARAMS;
error = DoIO(ior);
if (error)
printf("SetParams, error %d\n", error);
}
void
Set7Wire(ior)
IOSER *ior;
{
short error;
if (IosrIP)
AbortIO(&Iosr);
ior->IOSer.io_Command = SDCMD_SETPARAMS;
ior->io_SerFlags |= SERF_7WIRE;
error = DoIO(ior);
ior->io_SerFlags &= ~SERF_7WIRE;
if (error)
printf("SetParams, error %d\n", error);
}
void
Disconnect(dropdtr)
{
short retry = (IgnoreDTR) ? 2 : 10;
ulog(1, "Disconnect drop=%d", dropdtr);
HaveConnectMsg = 0;
HaveLogin = 0;
HavePasswd = 0;
LoginBuf[0] = 0;
PasswdBuf[0] = 0;
Index = 0;
State = ST_WAITCD;
while (dropdtr && DeviceInUse() == 0) {
short i;
RxDisable();
if (IgnoreDTR) {
if (ModemType != 'd') {
Delay(70);
SerPuts("+++");
Delay(70);
SerPuts("\010\010\r");
Delay(10);
SerPuts("ATH0\r");
Delay(120);
}
} else {
CloseDevice(&Iosr);
Iosr.IOSer.io_Device = NULL; /* so xexit doesn't reclose */
for (i = 0; i < 5; ++i) { /* 5 seconds */
Delay(50);
if (SetSignal(SIGBREAKF_CTRL_C, 0) & SIGBREAKF_CTRL_C)
xexit(23);
}
/*
* Use Iosr to re-open serial device so we don't loose
* our config.
*/
if (OpenDevice(DeviceName, DeviceUnit, &Iosr, 0)) {
Iosr.IOSer.io_Device = NULL;
xexit(22);
}
Iosw.IOSer.io_Device = Iosr.IOSer.io_Device;
Iosw.IOSer.io_Unit = Iosr.IOSer.io_Unit;
SetParams(&Iosw);
}
/*
* Loop until carrier lost
*/
Iosw.IOSer.io_Command = SDCMD_QUERY;
DoIO(&Iosw);
if (IgnoreCD)
Iosw.io_Status &= ~CIAF_COMCD;
RxEnable();
if ((Iosw.io_Status & CIAF_COMCD) != 0)
break;
if (--retry == 0) {
if (IgnoreDTR == 0)
puts("Getty: unable to disconnect!");
break;
}
}
if (DeviceInUse() == 0)
InitModem();
}
void
InitModem()
{
char buf[64];
short i;
RxDisable();
ulog(1, "Init Modem");
Iosw.io_Baud = Bauds[0]; /* reset baud rate */
BIndex = 0;
SetParams(&Iosw);
RxEnable();
switch(ModemType) {
case 'm': /* Multi Modem */
SerPuts("\010\010\r");
Delay(10);
SerPuts("AT\r");
Delay(50);
sprintf(buf, "ATM%dS0=%dX4$BA%d&E%d\r",
SpeakerLevel,
AnswerRing,
!BaudAdjust,
(Wire7) ? 4 : 3
);
SerPuts(buf);
break;
case 'h':
SerPuts("\010\010\r");
Delay(10);
SerPuts("ATZ\r");
Delay(120);
strcpy(buf, "AT");
if (SpeakerOpt)
sprintf(buf + strlen(buf), "M%d", SpeakerLevel);
sprintf(buf + strlen(buf), "S0=%d", AnswerRing);
strcat(buf, "\r");
SerPuts(buf);
break;
case 'd':
SerPuts("\010\010\r");
break;
}
for (i = 0; i < arysize(AtFields) && AtFields[i]; ++i) {
Delay(50);
SerPuts(AtFields[i]);
SerPuts("\r");
}
Delay(20);
ClearRecv();
Index = 0;
}
void
DoOptions(ac, av)
char *av[];
{
short i;
short bi = 0;
short fi = 0;
long v;
for (i = 1; i < ac; ++i) {
char *ptr = av[i];
if (*ptr != '-') {
if (fi != arysize(AtFields))
AtFields[fi++] = ptr;
else
puts("AT field overflow");
continue;
}
if (*++ptr) /* skip - */
++ptr; /* and option */
v = atoi(ptr);
switch(ptr[-1]) {
case '0':
ZeroOption = 1;
break;
case '7':
Wire7 = 1;
break;
case 'S':
DeviceName = ptr;
break;
case 'U':
DeviceUnit = v;
break;
case 'M':
ModemType = *ptr;
break;
case 'A':
BaudAdjust = 1;
break;
case 'B':
if (bi != arysize(Bauds))
Bauds[bi++] = v;
else
puts("-B field overflow");
break;
case 'm':
SpeakerOpt = 1;
SpeakerLevel = v;
break;
case 'r':
AnswerRing = v;
break;
case 'h':
IgnoreCD = !v;
break;
case 'c':
IgnoreConnect = !v;
break;
case 'd':
IgnoreDTR = !v;
break;
case 'x':
LogLevel = v;
LogToStdout = (v >= 0);
break;
default:
printf("Warning, Bad option: -%s\n", ptr);
break;
}
}
if (fi && fi != arysize(AtFields))
AtFields[fi] = NULL;
if (bi && bi != arysize(Bauds))
Bauds[bi] = 0;
}
DeviceInUse()
{
return(Iosr.IOSer.io_Device->dd_Library.lib_OpenCnt > 1);
}